// 使用此源代码受 BSD 风格许可证约束
// 该许可证可以在许可证文件中找到
//
// 作者: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef THREADSAFE_QUEUE_H
#define THREADSAFE_QUEUE_H

#include <cassert>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <optional>
#include <vector>

#include "CopyPolicy.h"

namespace cytoolkit {

/**
 * @brief 线程安全阻塞队列
 * 支持移动语义和完美转发，提供更高效的性能
 */
template <typename T>
class ThreadSafeQueue : NonCopyable{
public:
    using value_type = T;
    using container_type = std::deque<T>;

    ThreadSafeQueue() = default;

    /**
     * @brief 带容量限制的构造函数
     * @param capacity 队列最大容量
     */
    explicit ThreadSafeQueue(size_t capacity) : capacity_(capacity) {}

    ~ThreadSafeQueue() = default;

    // ==================== 生产者接口 ====================

    /**
     * @brief 将元素放入队列（左值引用版本）
     * @param value 要放入队列的元素
     * @return 是否成功放入（如果队列已满且非阻塞则返回false）
     */
    bool push(const T& value) {
        std::unique_lock lock(mutex_);
        if (capacity_ > 0 && queue_.size() >= capacity_) {
            return false;
        }

        queue_.push_back(value);
        lock.unlock();
        notEmpty_.notify_one();
        return true;
    }

    /**
     * @brief 将元素放入队列（右值引用版本）
     * @param value 要放入队列的元素（将被移动）
     * @return 是否成功放入
     */
    bool push(T&& value) {
        std::unique_lock lock(mutex_);
        if (capacity_ > 0 && queue_.size() >= capacity_) {
            return false;
        }

        queue_.push_back(std::move(value));
        lock.unlock();
        notEmpty_.notify_one();
        return true;
    }

    /**
     * @brief 阻塞式放入元素（如果队列满则等待）
     * @param value 要放入队列的元素
     */
    void pushWait(const T& value) {
        std::unique_lock lock(mutex_);
        if (capacity_ > 0) {
            notFull_.wait(lock, [this] { return queue_.size() < capacity_; });
        }

        queue_.push_back(value);
        notEmpty_.notify_one();
    }

    /**
     * @brief 带超时的放入操作
     * @param value 要放入队列的元素
     * @param timeout 超时时间
     * @return 是否成功放入
     */
    template <typename Rep, typename Period>
    bool pushTimeout(const T& value,
                     const std::chrono::duration<Rep, Period>& timeout) {
        std::unique_lock lock(mutex_);
        if (capacity_ > 0) {
            if (!notFull_.wait_for(lock, timeout, [this] {
                    return queue_.size() < capacity_;
                })) {
                return false;  // 超时
            }
        }

        queue_.push_back(value);
        notEmpty_.notify_one();
        return true;
    }

    /**
     * @brief 构造元素并放入队列（完美转发）
     * @param args 构造元素的参数
     * @return 是否成功放入
     */
    template <typename... Args>
    bool emplace(Args&&... args) {
        std::unique_lock lock(mutex_);
        if (capacity_ > 0 && queue_.size() >= capacity_) {
            return false;
        }

        queue_.emplace_back(std::forward<Args>(args)...);
        lock.unlock();
        notEmpty_.notify_one();
        return true;
    }

    /**
     * @brief 批量放入元素
     * @param first 起始迭代器
     * @param last 结束迭代器
     * @return 成功放入的元素数量
     */
    template <typename InputIt>
    size_t pushRange(InputIt first, InputIt last) {
        size_t count = 0;
        std::unique_lock lock(mutex_);

        for (auto it = first; it != last; ++it) {
            if (capacity_ > 0 && queue_.size() >= capacity_) {
                break;
            }
            queue_.push_back(*it);
            ++count;
        }

        if (count > 0) {
            lock.unlock();
            notEmpty_.notify_all();  // 通知所有消费者
        }
        return count;
    }

    // ==================== 消费者接口 ====================

    /**
     * @brief 从队列中取出元素（阻塞直到有元素可用）
     * @return 取出的元素
     */
    T pop() {
        std::unique_lock lock(mutex_);
        // 使用 while 循环避免虚假唤醒
        notEmpty_.wait(lock, [this] { return !queue_.empty() || shutdown_; });

        if (shutdown_ && queue_.empty()) {
            throw std::runtime_error("Queue has been shutdown");
        }

        assert(!queue_.empty());
        T front(std::move(queue_.front()));
        queue_.pop_front();

        if (capacity_ > 0) {
            lock.unlock();
            notFull_.notify_one();  // 通知可能等待的生产者
        }
        return front;
    }

    /**
     * @brief 尝试从队列中取出元素（非阻塞）
     * @return 如果队列不为空返回元素，否则返回 std::nullopt
     */
    std::optional<T> tryPop() {
        std::lock_guard lock(mutex_);
        if (queue_.empty()) {
            return std::nullopt;
        }

        T front(std::move(queue_.front()));
        queue_.pop_front();

        if (capacity_ > 0) {
            notFull_.notify_one();
        }
        return front;
    }

    /**
     * @brief 带超时的元素取出操作
     * @param timeout 超时时间
     * @return 如果超时前有元素可用返回元素，否则返回 std::nullopt
     */
    template <typename Rep, typename Period>
    std::optional<T> popTimeout(
        const std::chrono::duration<Rep, Period>& timeout) {
        std::unique_lock lock(mutex_);
        bool notTimeout = notEmpty_.wait_for(
            lock, timeout, [this] { return !queue_.empty() || shutdown_; });

        if (!notTimeout) {
            return std::nullopt;  // 超时
        }

        if (shutdown_ && queue_.empty()) {
            return std::nullopt;  // 队列已关闭且为空
        }

        T front(std::move(queue_.front()));
        queue_.pop_front();

        if (capacity_ > 0) {
            notFull_.notify_one();
        }
        return front;
    }

    /**
     * @brief 批量取出元素
     * @param maxCount 最大取出数量
     * @return 取出的元素容器
     */
    std::vector<T> popBulk(
        size_t maxCount = std::numeric_limits<size_t>::max()) {
        std::vector<T> result;
        std::unique_lock lock(mutex_);

        notEmpty_.wait(lock, [this] { return !queue_.empty() || shutdown_; });

        if (shutdown_ && queue_.empty()) {
            return result;  // 返回空结果
        }

        while (!queue_.empty() && result.size() < maxCount) {
            result.emplace_back(std::move(queue_.front()));
            queue_.pop_front();
        }

        if (capacity_ > 0 && !result.empty()) {
            lock.unlock();
            notFull_.notify_all();  // 通知所有可能等待的生产者
        }
        return result;
    }

    // ==================== 队列管理接口 ====================

    /**
     * @brief 清空队列并返回所有元素
     * @return 包含原队列所有元素的容器
     */
    container_type drain() {
        container_type result;
        {
            std::lock_guard lock(mutex_);
            result = std::move(queue_);
        }

        if (capacity_ > 0) {
            notFull_.notify_all();  // 通知所有可能等待的生产者
        }
        return result;
    }

    /**
     * @brief 清空队列
     */
    void clear() {
        std::lock_guard lock(mutex_);
        queue_.clear();

        if (capacity_ > 0) {
            notFull_.notify_all();
        }
    }

    /**
     * @brief 优雅关闭队列，唤醒所有等待线程
     */
    void shutdown() {
        {
            std::lock_guard lock(mutex_);
            shutdown_ = true;
        }
        notEmpty_.notify_all();
        notFull_.notify_all();
    }

    /**
     * @brief 重新启动已关闭的队列
     */
    void restart() {
        std::lock_guard lock(mutex_);
        shutdown_ = false;
    }

    // ==================== 状态查询接口 ====================

    /**
     * @brief 获取队列大小
     * @return 队列中元素的数量
     */
    size_t size() const {
        std::lock_guard lock(mutex_);
        return queue_.size();
    }

    /**
     * @brief 检查队列是否为空
     * @return 如果队列为空返回 true，否则返回 false
     */
    bool empty() const {
        std::lock_guard lock(mutex_);
        return queue_.empty();
    }

    /**
     * @brief 检查队列是否已满（仅在设置容量时有效）
     * @return 如果队列已满返回 true，否则返回 false
     */
    bool full() const {
        if (capacity_ == 0)
            return false;
        std::lock_guard lock(mutex_);
        return queue_.size() >= capacity_;
    }

    /**
     * @brief 获取队列容量
     * @return 队列容量（0表示无限制）
     */
    size_t capacity() const { return capacity_; }

    /**
     * @brief 检查队列是否已关闭
     * @return 如果队列已关闭返回 true，否则返回 false
     */
    bool isShutdown() const {
        std::lock_guard lock(mutex_);
        return shutdown_;
    }

    /**
     * @brief 查看队列头部元素（不取出）
     * @return 队列头部元素的引用（队列为空时行为未定义）
     */
    const T& front() const {
        std::lock_guard lock(mutex_);
        assert(!queue_.empty());
        return queue_.front();
    }

    /**
     * @brief 查看队列尾部元素（不取出）
     * @return 队列尾部元素的引用（队列为空时行为未定义）
     */
    const T& back() const {
        std::lock_guard lock(mutex_);
        assert(!queue_.empty());
        return queue_.back();
    }

private:
    mutable std::mutex mutex_;
    std::condition_variable notEmpty_;
    std::condition_variable notFull_;
    container_type queue_;
    size_t capacity_ = 0;  // 0表示无容量限制
    bool shutdown_ = false;
};

}  // namespace cytoolkit

#endif  // THREADSAFE_QUEUE_H